/*
 * OREKIT-X
 * Copyright 2002-2008 CS Communication & Systemes
 * 
 * Parts of this software package have been licensed to CS
 * Communication & Systemes (CS) under one or more contributor license
 * agreements.  See the NOTICE file distributed with this work for
 * additional information.
 *  
 * This is an experimental copy of OREKIT from www.orekit.org.
 * Please use the original OREKIT from orekit.org for normal work
 * unrelated to this research project.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You
 * may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
package ore.frames;

import ore.Frame;
import ore.Transform;
import ore.errors.OrekitException;
import ore.time.AbsoluteDate;

import org.apache.commons.math.geometry.Rotation;

/** 
 * Several predefined reference frames are implementeded in OREKIT.
 * They are linked together in a tree with the <i>Geocentric
 * Celestial Reference Frame</i> (GCRF) as the root of the tree.
 * 
 * <h5> International Terrestrial Reference Frame 2005 </h5>
 * 
 * This frame is the current (as of 2008) reference realization of
 * the International Terrestrial Reference System produced by IERS.
 * 
 * It is described in <a
 * href="http://www.iers.org/documents/publications/tn/tn32/tn32.pdf">
 * IERS conventions (2003)</a>. It replaces the Earth Centered Earth Fixed
 * frame which is the reference frame for GPS satellites.
 * 
 * This frame is used to define position on solid Earth. It rotates with
 * the Earth and includes the pole motion with respect to Earth crust as
 * provided by {@link ore.data.DataProvidersManager IERS data}.
 * Its pole axis is the IERS Reference Pole (IRP).
 * 
 * OREKIT proposes all the intermediate frames used to build this specific frame.
 * This implementation follows the new non-rotating origin paradigm
 * mandated by IAU 2000 resolution B1.8. It is therefore based on
 * Celestial Ephemeris Origin (CEO-based) and Earth Rotating Angle.
 * 
 * <h5> Classical paradigm: equinox-based transformations </h5>
 * 
 * The classical paradigm used prior to IERS conventions 2003 is equinox based and
 * uses more intermediate frames. Only some of these frames are supported in Orekit.
 * 
 * The following is a schematic for the predefined reference frames
 * tree.
 * 
 * <pre>
 *                                                GCRF
 *                                                 |
 *                                                 |---------------------------------------------
 *                                                 |                       |     Frame bias     |
 *                                                 |                       |                 EME2000
 *                                                 |                       |                    |
 *                                                 |                       | Precession effects |
 *                                                 |                       |                    |
 *           Bias, Precession and Nutation effects |                     MEME                 MEME  (Mean Equator of Date)
 *                                                 |                       |             w/o EOP corrections
 *                                                 |                       |  Nutation effects  |
 *    (Celestial Intermediate Reference Frame) CIRF2000                    |                    |
 *                                                 |                     TEME                 TEME  (True Equator of Date)
 *                          Earth natural rotation |                       |             w/o EOP corrections
 *                                                 |-------------          |    Sidereal Time   |
 *                                                 |            |          |                    |
 *  (Terrestrial Intermediate Reference Frame) TIRF2000     TIRF2000      PEF                  PEF  (Pseudo Earth Fixed)
 *                                                 |    w/o tidal effects                w/o EOP corrections
 *                                     Pole motion |            |
 *                                                 |            |
 * (International Terrestrial Reference Frame) ITRF2005     ITRF2005
 *                                                      w/o tidal effects
 * </pre>
 * 
 * @author Guylaine Prat
 * @author Luc Maisonobe
 * @author Pascal Parraud
 */
public class FramesFactory {

    /** 
     * The GCRF frame is the root frame in the frame tree.
     * @return The unique instance of the GCRF frame
     */
    public final static Frame getGCRF() {
        return Frame.Root;
    }
    /** 
     * The EME2000 frame is also called the J2000 frame.  The former
     * denomination is preferred in Orekit.
     * @return Unique instance of the EME2000 frame
     */
    public final static Frame getEME2000() {
        return EME2000Frame.Instance();
    }
    /** 
     * @return CIRF2000 reference frame singleton.
     * @exception OrekitException The precession-nutation model data
     * embedded in the library cannot be read.
     */
    public final static Frame getCIRF2000() throws OrekitException {
        return CIRF2000Frame.Instance();
    }
    /** 
     * @return ITRF2005 reference frame, ignoring tidal effects.
     * @exception OrekitException if the precession-nutation model data embedded in the
     * library cannot be read.
     */
    public final static Frame getITRF2005() throws OrekitException {
        return getITRF2005(true);
    }
    /** 
     * @param ignoreTidalEffects if true, tidal effects are ignored
     * @return ITRF2005 reference frame singleton.
     * @exception OrekitException if the precession-nutation model data embedded in the
     * library cannot be read.
     */
    public final static Frame getITRF2005(final boolean ignoreTidalEffects) throws OrekitException {
        synchronized (FramesFactory.class) {

            if (ignoreTidalEffects) {
                if (itrf2005WithoutTidalEffects == null) {
                    itrf2005WithoutTidalEffects =
                        new ITRF2005Frame(false, AbsoluteDate.J2000_EPOCH, "ITRF2005");
                }
                return itrf2005WithoutTidalEffects;
            } else {
                if (itrf2005WithTidalEffects == null) {
                    itrf2005WithTidalEffects =
                        new ITRF2005Frame(true, AbsoluteDate.J2000_EPOCH, "ITRF2005 w/o tides");
                }
                return itrf2005WithTidalEffects;
            }
        }

    }
    /** 
     * @return TIRF2000 reference frame, ignoring tidal effects
     * @exception OrekitException if the precession-nutation model data embedded in the
     * library cannot be read.
     */
    public final static Frame getTIRF2000() throws OrekitException {
        return getTIRF2000(true);
    }

    /** Get the TIRF2000 reference frame.
     * @param ignoreTidalEffects if true, tidal effects are ignored
     * @return the selected reference frame singleton.
     * @exception OrekitException if the precession-nutation model data embedded in the
     * library cannot be read.
     */
    public final static Frame getTIRF2000(final boolean ignoreTidalEffects) throws OrekitException {
        synchronized (FramesFactory.class) {

            if (ignoreTidalEffects) {
                if (tirf2000WithoutTidalEffects == null) {
                    tirf2000WithoutTidalEffects =
                        new TIRF2000Frame(false, AbsoluteDate.J2000_EPOCH, "TIRF2000");
                }
                return tirf2000WithoutTidalEffects;
            } else {
                if (tirf2000WithTidalEffects == null) {
                    tirf2000WithTidalEffects =
                        new TIRF2000Frame(true, AbsoluteDate.J2000_EPOCH, "TIRF2000 w/o tides");
                }
                return tirf2000WithTidalEffects;
            }

        }
    }
    /** 
     * @return VEIS 1950 reference frame singleton.
     */
    public final static Frame getVeis1950() {
        synchronized (FramesFactory.class) {

            if (veis1950 == null) {
                veis1950 = new Frame(getEME2000(),
                                     new Transform(new Rotation(0.99998141186121629647,
                                                                -2.01425201682020570e-5,
                                                                -2.43283773387856897e-3,
                                                                5.59078052583013584e-3,
                                                                true)),
                                     "VEIS1950");
            }

            return veis1950;

        }
    }

    /** Get the PEF reference frame.
     * <p>
     * The applyEOPCorr parameter is available mainly for testing purposes or for
     * consistency with legacy software that don't handle EOP parameters. Beware
     * that setting this parameter to {@code false} leads to very crude accuracy
     * (order of magnitudes for errors are above 100m in LEO and above 1000m in GEO).
     * </p>
     * @param applyEOPCorr if true, EOP corrections are applied (here dut1 and lod)
     * @return the selected reference frame singleton.
     * @exception OrekitException if the nutation model data embedded in the
     * library cannot be read.
     */
    public final static Frame getPEF(final boolean applyEOPCorr) throws OrekitException {
        synchronized (FramesFactory.class) {

            if (applyEOPCorr) {
                if (pefWithEopCorrections == null) {
                    pefWithEopCorrections =
                        new PEFFrame(true, AbsoluteDate.J2000_EPOCH, "PEF with EOP");
                }
                return pefWithEopCorrections;
            } else {
                if (pefWithoutEopCorrections == null) {
                    pefWithoutEopCorrections =
                        new PEFFrame(false, AbsoluteDate.J2000_EPOCH, "PEF without EOP");
                }
                return pefWithoutEopCorrections;
            }

        }
    }

    /** Get the TEME reference frame.
     * <p>
     * The applyEOPCorr parameter is available mainly for testing purposes or for
     * consistency with legacy software that don't handle EOP parameters. Beware
     * that setting this parameter to {@code false} leads to very crude accuracy
     * (order of magnitudes for errors are about 1m in LEO and 10m in GEO).
     * </p>
     * @param applyEOPCorr if true, EOP corrections are applied (here, nutation)
     * @return the selected reference frame singleton.
     * @exception OrekitException if the nutation model data embedded in the
     * library cannot be read.
     */
    public final static Frame getTEME(final boolean applyEOPCorr) throws OrekitException {
        synchronized (FramesFactory.class) {

            if (applyEOPCorr) {
                if (temeWithEopCorrections == null) {
                    temeWithEopCorrections =
                        new TEMEFrame(true, AbsoluteDate.J2000_EPOCH, "TEME with EOP");
                }
                return temeWithEopCorrections;
            } else {
                if (temeWithoutEopCorrections == null) {
                    temeWithoutEopCorrections =
                        new TEMEFrame(false, AbsoluteDate.J2000_EPOCH, "TEME without EOP");
                }
                return temeWithoutEopCorrections;
            }

        }
    }

    /** Get the MEME reference frame.
     * <p>
     * The applyEOPCorr parameter is available mainly for testing purposes or for
     * consistency with legacy software that don't handle EOP parameters. Beware
     * that setting this parameter to {@code false} leads to very crude accuracy
     * (order of magnitudes for errors are about 1m in LEO and 10m in GEO).
     * </p>
     * @param applyEOPCorr if true, EOP corrections are applied (EME2000/GCRF bias compensation)
     * @return the selected reference frame singleton.
     * @exception OrekitException if EOP parameters are desired but cannot be read
     */
    public final static Frame getMEME(final boolean applyEOPCorr) throws OrekitException {
        synchronized (FramesFactory.class) {

            if (applyEOPCorr) {
                if (memeWithEopCorrections == null) {
                    memeWithEopCorrections =
                        new MEMEFrame(true, AbsoluteDate.J2000_EPOCH, "MEME with EOP");
                }
                return memeWithEopCorrections;
            } else {
                if (memeWithoutEopCorrections == null) {
                    memeWithoutEopCorrections =
                        new MEMEFrame(false, AbsoluteDate.J2000_EPOCH, "MEME without EOP");
                }
                return memeWithoutEopCorrections;
            }

        }
    }


    private static Frame itrf2005WithoutTidalEffects = null;
    private static Frame itrf2005WithTidalEffects = null;
    private static Frame tirf2000WithoutTidalEffects = null;
    private static Frame tirf2000WithTidalEffects = null;
    private static Frame veis1950 = null;
    private static Frame pefWithoutEopCorrections = null;
    private static Frame pefWithEopCorrections = null;
    private static Frame temeWithoutEopCorrections = null;
    private static Frame temeWithEopCorrections = null;
    private static Frame memeWithoutEopCorrections = null;
    private static Frame memeWithEopCorrections = null;


    private FramesFactory() {
        super();
    }
}
